package com.biostime.qdingding.modules.qd.service;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.biostime.qdingding.modules.qd.api.BasicApi;
import com.biostime.qdingding.modules.qd.api.dto.BalanceDto;
import com.biostime.qdingding.modules.qd.api.dto.ContractDto;
import com.biostime.qdingding.modules.qd.api.dto.CoursesectionDto;
import com.biostime.qdingding.modules.qd.dao.ContractDao;
import com.biostime.qdingding.modules.qd.dao.CourseDao;
import com.biostime.qdingding.modules.qd.entity.Contract;
import com.biostime.qdingding.modules.qd.entity.Course;
import com.biostime.qdingding.modules.qd.entity.CourseOrder;
import com.biostime.qdingding.modules.qd.entity.Member;
import com.biostime.qdingding.modules.qd.entity.Student;

/**
 * @author chenweicheng
 * 课程预约，加入等位条件判断
 * @version 2015-12-08
 */
@Transactional
@Service
public class BookConfirmService {
	
	//浮动天数
	private static final int day=36*30;
	@Autowired
	private MemberService memberService;
	@Autowired
	private StudentService studentService;
	@Autowired
	private TransrecordService transrecordService;
	@Autowired
	private CourseDao coursedao;
	@Autowired
	private ContractDao contractDao;
	@Autowired
	private PriceService priceService;
	@Autowired
	private ContractService contractService;

	/**
	 *  预约时间限制，前一天晚上10点后不能预约
	 * @version 2015-12-08
	 */
	public  boolean notOrderTime(String courseId,int type){
		Course course = coursedao.apiGetInOrOut(String.valueOf(type), courseId);
		boolean flag = true;
		if(course != null && course.getOndate() != null){	
			
			//判断当前时间是否在前一天晚上的10点钟
			if(new Date().getTime()/1000<(course.getOndate().getTime()/1000-(60*60*2))){
				flag = true;
			}else{
				flag = false;
			}
			
		}
		return flag;
	}	
	
	/**
	 *  上课时间的前一天早上9点钟后不能被取消
	 * @version 2016-03-07
	 */
	public  boolean notCancelTime(String courseId,int type){
		Course course = coursedao.apiGetInOrOut(String.valueOf(type), courseId);
		boolean flag = true;
		if(course != null && course.getOndate() != null){	
			
			//判断当前时间是否在前一天晚上的9点钟
			if(new Date().getTime()/1000<(course.getOndate().getTime()/1000-(60*60*15))){
				flag = true;
			}else{
				flag = false;
			}
			
		}
		return flag;
	}	
	
	/**
	 *  1，前一天早上9点后能请假
	 *  2，课程开始后不能请假
	 *  3，并且判断是扣费前请假还是扣费后请假
	 *  4，前一天晚上5点后不是后台请假会提示请联系顾问请假
	 *  @version 2016-03-07
	 */		
	public  HashMap<String,Object> notLeaveTime(CourseOrder courseOrder ,String fromType){
		
		//是否到请假时间
		boolean flag = false;
		
		//是否已扣费
		boolean ifCharge = false;
		
		//返回信息
		String errMessage = "请假失败,未到请假时间";
		
		if(courseOrder != null){
			
			//暂定用course表
			Course course = coursedao.apiGetInOrOut("0", String.valueOf(courseOrder.getCourseId()));
			CoursesectionDto dto = coursedao.apiGetSection(String.valueOf(course.getSectionId()));
			String starton = "1";
			if(dto != null){
				starton = dto.getStarton();
			}
			double hour = Double.parseDouble(starton);
			
			if(course != null && course.getOndate() != null){	
				long ondateTime = course.getOndate().getTime();
				
				//判断时间是否在前一天早上9点且在晚上10点
				if((new Date().getTime()/1000 > (ondateTime/1000-(60*60*15))) && 
						(new Date().getTime() < ondateTime+hour*60*60*1000)){
					flag = true;
					
					//判断时间是否在10点以后且是否扣费
					if(new Date().getTime()/1000 >= (ondateTime/1000-(60*60*2)) && courseOrder.getPaid() == 1){
						ifCharge = true;
					}
					
					//判断时间是否在5点以后且是否来自后台
					if(new Date().getTime()/1000 >= (ondateTime/1000-(60*60*7)) && !fromType.equals("background")){ 
						flag = false;
						errMessage = "请联系顾问请假";
					}
					
				}
				
			}			
		}
			
		if(flag){
			errMessage = "请假成功";
		}
		HashMap<String,Object> map = new HashMap<String,Object>();
		map.put("flag", flag);
		map.put("ifCharge", ifCharge);
		map.put("errMessage", errMessage);
		
		return map;
	}	
		
	private boolean enoughForFullPrice(BalanceDto balance,double priceBefore){
		if(balance==null)return false;
		else return balance.getSumPay()-balance.getSumCost()-balance.getSumFreeze()>priceBefore;
	}
	
	private boolean enoughForDiscount(BalanceDto balance,double priceAfter){
		if(balance==null)return false;
		else return balance.getSumPay()-balance.getSumCost()-balance.getSumFreeze()>priceAfter;
	}
	
	private HashMap<String,Object> getPrice(String studentId,Course course){
		HashMap<String,Object> result=null;
		try{
			result=priceService.getPriceMap(course, studentId);
		}catch(Exception e){}
		return result;
	}
	
	private boolean inLimitTime(String studentId){
		Contract contract = contractDao.getByStudentId(Integer.parseInt(studentId));
		if(contract!=null&&contract.getLimitDate().compareTo(new Date())>0)return true;
		return false;
	}
	
	/**
	 * 判断学生年龄段是否符合该课程
	 */
	public boolean judgeAge(Student student,Course course){
		boolean flag = false;
		flag = studentService.apiCheckAge(student.getId(), course, day); 
		return flag;
	}
	
	public enum BookResult{
		success(0,1,"预约成功"),
		notEnoughMoney(1,1,"余额不足"),
		justEnoughForDiscount(0,1,"由于优惠变动，目前您的余额未必足够支付，最终结果以实际扣费为准"),
		timeLimit(1,1,"余额已到期，无法预约"),
		contractUnavailable(1,1,"未签订合同或合同已到期，无法预约"),
		outOfAge(1,1,"您的宝宝年龄不适合此课程"),
		typeError(1,1,"暂不提供户外课程预约"),
		unpaid(1,1,"请付定金或余款"),
		unpaidIn7days(1,1,"请缴清合同余款"),
		notOrderTime(1,1,"已过预约时间");
		
		private int errCode;
		private int subCode;
		private String msg;
		private BookResult(int errCode,int subCode,String msg){
			this.errCode=errCode;
			this.subCode=subCode;
			this.msg=msg;
		}
		public int getErrCode() {
			return errCode;
		}
		public int getSubCode() {
			return subCode;
		}
		public String getMsg() {
			return msg;
		}
	}
	
	
	public BookResult confirm(String userId,String studentId,String courseId,int type){
		
		if(!studentId.equals(String.valueOf(BasicApi.defaultStudentId))){
			Member member=new Member();
			member.setId(userId);
			member=memberService.get(member);
			Student student=studentService.apiGetStudentById(studentId);
			if(type==0){
				
				Course course=null;
				
				//尚未判断户外课程年龄段，因为户外课程不存在年龄段
				course=coursedao.get(courseId);
				HashMap<String,Object> map=getPrice(studentId, course);
				double moneyBefore=(double)map.get("moneyBefore");
				double moneyAfter=(double)map.get("moneyAfter");
				BalanceDto balance=transrecordService.getBalance(student);
				
				//获取学员合同状态
				ContractFeeStatus cfs=this.getContractFeeStatus(studentId);
				
				switch(cfs){
				case contractInvalid:
				case contractOverdue:
					return BookResult.contractUnavailable;
				case lowerThenAmountBeyond7days:
					return BookResult.unpaidIn7days;
				case lowerThenDepositIn7days:
					return BookResult.unpaid;
				case fullpaid:
				default:
					if(!inLimitTime(studentId))return BookResult.timeLimit;
					else if(!studentService.apiCheckAge(student.getId(), course, day))return BookResult.outOfAge;
					else if(!enoughForDiscount(balance,moneyAfter))return BookResult.notEnoughMoney;
					else if(!enoughForFullPrice(balance,moneyBefore))return BookResult.justEnoughForDiscount;
					else if(!notOrderTime(courseId,type)) return BookResult.notOrderTime;
					return BookResult.success;
				}
			}	
			return BookResult.typeError;
		}
		return BookResult.typeError;	
	}
	
	//以下为合同状态
	public enum ContractFeeStatus{
		lowerThenDepositIn7days("在签订日期后7天内，充值金额小于订金","付30%或全款",false),
		lowerThenAmountIn7days("在签订日期后7天内，充值金额大于订金小于合同金额","请X月X日前付余款",true),
		lowerThenAmountBeyond7days("在签订日期后7天后，充值金额仍小于合同金额","请X月X日前付余款",false),
		fullpaid("已付全款","已付全款",true),
		contractOverdue("已过合同有效期 ","已过期",false),
		contractInvalid("合同被中止 ","已中止",false);
		private String desc;
		private String tips;
		private boolean bookAble;
		private ContractFeeStatus(String desc,String tips,boolean bookAble){
			this.desc=desc;
			this.tips=tips;
			this.bookAble=bookAble;
		}
		public String getDesc() {
			return desc;
		}
		public void setDesc(String desc) {
			this.desc = desc;
		}
		public String getTips() {
			return tips;
		}
		public ContractFeeStatus setTips(String tips) {
			this.tips = tips;
			return this;
		}
		public boolean isBookAble() {
			return bookAble;
		}
		public void setBookAble(boolean bookAble) {
			this.bookAble = bookAble;
		}
	}
	
	/**
	 * 获取合同状态
	 * @return
	 */
	public ContractFeeStatus getContractFeeStatus(String studentId){
		
		if(!studentId.equals(String.valueOf(BasicApi.defaultStudentId))){ 
			
			List<ContractDto> listContract=contractService.apiGetContract(studentId);			
			if(listContract != null && !listContract.isEmpty()){
				ContractDto contract=listContract.get(0);
				Student student=new Student(studentId);
				student=studentService.get(student);
				
				//判断合同是否过有效期
				if(contractOverdue(contract)){
					return ContractFeeStatus.contractOverdue;
				}
				
				//判断合同是否中止
				if(contract.getAbort() == 1){
					return ContractFeeStatus.contractInvalid;
				}
				double pay = transrecordService.apiGetRecharge(studentId, String.valueOf(contract.getId()));	

				//判断合同是否在7天之内
				if(in7days(contract)){
					
					//如果定金小于合同金额30%
					if(pay < contract.getAmount()*0.3){
						return ContractFeeStatus.lowerThenDepositIn7days; 
					}
					
					//如果定金小于合同金额,大于等于合同金额*0.3
					else if(pay < contract.getAmount() && pay >= contract.getAmount()*0.3){
						return ContractFeeStatus.lowerThenAmountIn7days.setTips(getTipsStr(contract));
					}
					
					//如果付全款
					else if(pay >= contract.getAmount()){
						return ContractFeeStatus.fullpaid;	
					}
					
				}else{
					if(pay < contract.getAmount()){
						return ContractFeeStatus.lowerThenAmountBeyond7days.setTips(getTipsStr(contract));
					}else{
						return ContractFeeStatus.fullpaid;	
					}
					
				}					
				return ContractFeeStatus.fullpaid;					
			}		
		}
		
		return ContractFeeStatus.contractOverdue;	
		
	}
	
	private boolean contractOverdue(ContractDto contract){
		Date time=contract.getEndDate();
		Date currentTime=new Date();
		if(time==null)return false;
		return time.before(currentTime);
	}
	
	private boolean in7days(ContractDto contract){
		Date time=contract.getSignDate();
		Calendar timeP7=Calendar.getInstance();
		timeP7.setTime(time);
		timeP7.add(Calendar.DATE, 7);
		Calendar currentTime=Calendar.getInstance();
		return currentTime.compareTo(timeP7)<0;
	}
	
	private String getTipsStr(ContractDto contract){	
		Date time=contract.getSignDate();
		Calendar cal = Calendar.getInstance();
		cal.setTime(new Date(time.getTime() + 7 * 24 * 60 * 60 * 1000)); 
	    int day = cal.get(Calendar.DATE);
	    int month = cal.get(Calendar.MONTH) + 1;    		
		return month+"月"+day+"日前付余款";
	}
	
}
